package com.hm.hall.commons.util;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 作者 luhong E-mail:luhong@hoomic.com
 * @version 创建时间：2016年4月18日 上午9:52:55
 * 类说明
 */
public class SyncUtils {


    /**
     * 每天会清理的  同步锁, 工具的key前缀 ( 带有此前缀的key 每天凌晨会释放掉, 节约内存)
     */
    public static final String AUTO_CLEAR_KEY_PREFIX = "AUTO_CLEAR_";
    private static final Map<String, Object> LOCK = new ConcurrentHashMap<String, Object>();
    private static final Object LOCK_OBJECT = new Object();
    private static final Map<String, ReentrantLock> REENTRANT_LOCK_MAP = new ConcurrentHashMap<>();

    /**
     * 用 key 获得同一个自动销毁的 ReentrantLock 锁对象  (线程安全,第二天凌晨清理自动销毁的锁对象)
     */
    public static Object getReentrantLock(String key) {
        ReentrantLock lock = REENTRANT_LOCK_MAP.get(key);
        if (null == lock) {
            // 防止同个key并发,多个null 而出现多个对象的问题
            synchronized (LOCK_OBJECT) {
                lock = SyncUtils.REENTRANT_LOCK_MAP.get(key);
                if (null == lock) {
                    lock = new ReentrantLock();
                    SyncUtils.REENTRANT_LOCK_MAP.put(key, lock);
                }
            }
        }
        return getAutoDestroyLockObject(key);
    }


    /**
     * 用 key 获得同一个自动销毁的锁对象  (线程安全,第二天凌晨清理自动销毁的锁对象)
     */
    public static Object getLockObject(String key) {
        return getAutoDestroyLockObject(key);
    }

    /**
     * 用 key 获得同一个自动销毁的锁对象  (线程安全,第二天凌晨清理自动销毁的锁对象)
     */
    private static Object getAutoDestroyLockObject(String key) {
        key = SyncUtils.AUTO_CLEAR_KEY_PREFIX + key;

        Object obj = LOCK.get(key);
        if (null == obj) {
            // 防止同个key并发,多个null 而出现多个对象的问题
            synchronized (LOCK_OBJECT) {
                obj = LOCK.get(key);
                if (null == obj) {
                    obj = new Object();
                    LOCK.put(key, obj);
                }
            }
        }
        return obj;
    }


    /**
     * 用 用户ID 获得同一个锁对象  获得同一个自动销毁的锁对象  (线程安全,第二天凌晨清理自动销毁的锁对象)
     */
    public static Object getLockObject(long userId) {
        return getAutoDestroyLockObject(userId + "");
    }


    /**
     * 移除锁对象的key
     */
    public static void removeLockKey(String key) {
        LOCK.remove(key);
    }


    /**
     * 用key的前缀 清理  锁对象的key
     */
    public static void clearLockKeyByPrefix(String keyPrefix) {
        Set<String> keys = LOCK.keySet();
        for (String key : keys) {
            if (key.startsWith(keyPrefix)) {
                LOCK.remove(key);
            }
        }
    }

    /**
     * 清理  锁对象
     */
    public static void clearSyncUtilsLockObj() {
        clearLockKeyByPrefix(SyncUtils.AUTO_CLEAR_KEY_PREFIX);
        REENTRANT_LOCK_MAP.clear();
    }


    public static void main(String[] args) {
        // 清理无效对象,测试 ,,,,结论超快的不用担心!!!
        String keyPrefix[] = {"1prefix", "2prefix", "3prefix", "4prefix", "5prefix", "6prefix", "7prefix", "8prefix", "9prefix", "10prefix"};

        for (int i = 0; i < 1000000; i++) {
            String key = keyPrefix[i % 10] + i;
            getLockObject(key);
        }

        System.out.println(LOCK.size());

        long sTime = System.currentTimeMillis();
        clearLockKeyByPrefix("2prefix");
        System.out.println(System.currentTimeMillis() - sTime);

        System.out.println(LOCK.size());
    }


}
